#include <iostream>
#include <vector>
#include <string>

#include <cstdio>

#include <sds/sfile.h>
#include <sds/sdataset.h>
#include <sds/sdataview.h>

using namespace std;
using namespace sds;

void Read(const string& cluname, const string& refname,
	  SDataView<unsigned char>& clu, SDataView<unsigned char>& ref,
	  vector<SInteger>& size) {
  SFile clufile(cluname);
  clu = clufile.getDataset(0).getDataView<unsigned char>();
  SFile reffile(refname);
  ref = reffile.getDataset(0).getDataView<unsigned char>();
  size = clu.getSize();
}

void Write(const string& trgname, SDataView<unsigned char>& clu,
	   const unsigned char col[256], vector<SInteger>& size) {
  SFile trgfile(trgname, SFile::CREATE);
  SDataset trg = trgfile.createDataset("classified", UINT8, size);
  for (int i = 0; i < size[0]; ++i) {
    for (int j = 0; j < size[1]; ++j) {
      clu[i][j] = col[clu[i][j]];
    }
  }
  trg.setDataView<unsigned char>(clu);
}


int main(int argc, const char *argv[]) {
  SDataView<unsigned char> clu;
  SDataView<unsigned char> ref;

  vector<SInteger> size;

  Read(argv[1], argv[2], clu, ref, size);

  int cr[256][256], r[256], s[256], fs[256];
  
  for (int i = 0; i < 256; ++i) {
    for (int j = 0; j < 256; ++j) {
      cr[i][j] = 0;
    }
    r[i] = 0; s[i] = 0; fs[i] = 0;
  }
  
  for (int i = 0; i < size[0]; ++i) {
    for (int j = 0; j < size[1]; ++j) {
      ++fs[clu[i][j]];
      if (ref[i][j] == 0) continue; 
      ++(cr[clu[i][j]][ref[i][j]]);
      ++(r[ref[i][j]]);
      ++(s[clu[i][j]]);
    }
  }
  unsigned char col[256];
  for (int i = 0; i < 256; ++i) {
    col[i] = 0;
    if (fs[i] >= 1000 * s[i]) continue;
    for (int j = 0; j < 256; ++j) {
      if (r[j] == 0) continue;
      if ((col[i] == 0 || cr[i][j] > cr[i][col[i]]) && 4 * cr[i][j] > s[i]) {
 	col[i] = j;
      }
    }
  }

  Write(argv[3], clu, col, size);
  return 0;
}
